---
title: Using Filters
description: Narrow search results with metadata filtering
edit-this-page-url: https://github.com/airweave-ai/airweave/blob/main/fern/docs/pages/search/filters.mdx
slug: search/filters
---

While vector search excels at finding semantically similar content, filters allow you to narrow results based on exact payload criteria. This combination of semantic search and filtering makes Airweave particularly powerful for finding specific information within large datasets.

## Why Filters Matter

Consider searching for "payment processing issues" across your connected systems. Without filters, you might get results from three years ago, from test environments, or from unrelated payment systems. Filters let you specify exactly which subset of data to search within.

## Filter Structure

Airweave uses Qdrant's filtering system, which provides a flexible way to express complex conditions. Filters consist of conditions combined with logical operators.

<Tip>
Try these filter examples in our interactive API playground.

[Open API Explorer →](/api-reference/collections/search-collection-advanced-collections-readable-id-search-post?explorer=true)
</Tip>

### Basic Filter Anatomy

```python
from qdrant_client.http.models import Filter, FieldCondition, MatchValue

filter = Filter(
    must=[
        FieldCondition(
            key="source_name",
            match=MatchValue(value="Stripe")
        )
    ]
)
```

## Logical Operators

Filters support three logical operators that can be combined to create complex queries:

### Must (AND)

All conditions in the `must` array must be satisfied. Think of this as an AND operation.

```python
Filter(
    must=[
        FieldCondition(key="source_name", match=MatchValue(value="GitHub")),
        FieldCondition(key="is_archived", match=MatchValue(value=False))
    ]
)
# Returns: GitHub items that are NOT archived
```

### Should (OR)

At least one condition in the `should` array must be satisfied. This creates an OR operation.

```python
Filter(
    should=[
        FieldCondition(key="priority", match=MatchValue(value="high")),
        FieldCondition(key="priority", match=MatchValue(value="critical"))
    ]
)
# Returns: Items with high OR critical priority
```

### Must Not (NOT)

None of the conditions in the `must_not` array can be satisfied. Use this to exclude results.

```python
Filter(
    must_not=[
        FieldCondition(key="status", match=MatchValue(value="resolved"))
    ]
)
# Returns: All items except those with resolved status
```

## Common Airweave Fields

Understanding the available fields is crucial for effective filtering. Here are the most commonly used fields across Airweave data sources:

### `source_name` field

The data source identifier. **Important**: This field is case-sensitive.

```python
# Correct - matches exactly
FieldCondition(key="source_name", match=MatchValue(value="Asana"))

# Incorrect - won't match "Asana"
FieldCondition(key="source_name", match=MatchValue(value="asana"))
```

### Timestamps

Timestamps use ISO 8601 format. Use `DatetimeRange` for date filtering:

```python
from qdrant_client.http.models import DatetimeRange
from datetime import datetime, timezone

FieldCondition(
    key="created_at",
    range=DatetimeRange(
        gte=datetime(2024, 1, 1, tzinfo=timezone.utc),
        lte=datetime(2024, 12, 31, tzinfo=timezone.utc)
    )
)
```

### Nested Payload

Nested fields can be accessed using dot notation:

```python
# Access nested metadata fields
FieldCondition(key="metadata.project_id", match=MatchValue(value="PROJ-123"))
FieldCondition(key="metadata.assignee", match=MatchValue(value="john@example.com"))
```

## Practical Examples

### Filter by Source

Find all content from a specific data source:

```python
search_request = SearchRequest(
    query="deployment procedures",
    filter=Filter(
        must=[
            FieldCondition(
                key="source_name",
                match=MatchValue(value="Confluence")
            )
        ]
    )
)
```

### Date Range Filtering

Find recent items within the last 30 days:

```python
from datetime import datetime, timedelta, timezone

thirty_days_ago = datetime.now(timezone.utc) - timedelta(days=30)

search_request = SearchRequest(
    query="bug reports",
    filter=Filter(
        must=[
            FieldCondition(
                key="created_at",
                range=DatetimeRange(gte=thirty_days_ago)
            )
        ]
    )
)
```

### Complex Multi-Source Query

Find high-priority items from multiple support systems:

```python
from qdrant_client.http.models import MatchAny

search_request = SearchRequest(
    query="customer complaints",
    filter=Filter(
        must=[
            FieldCondition(
                key="source_name",
                match=MatchAny(any=["Zendesk", "Intercom"])
            ),
            FieldCondition(
                key="priority",
                match=MatchValue(value="high")
            )
        ],
        must_not=[
            FieldCondition(
                key="status",
                match=MatchValue(value="closed")
            )
        ]
    )
)
```

### Handling Case Sensitivity

Since `source_name` is case-sensitive, use `MatchAny` to handle variations:

```python
# Case-insensitive source matching
FieldCondition(
    key="source_name",
    match=MatchAny(any=["Slack", "slack", "SLACK"])
)
```

## Advanced Filtering

### Combining Conditions

Create sophisticated filters by nesting conditions:

```python
Filter(
    must=[
        FieldCondition(key="source_name", match=MatchValue(value="GitHub")),
        Filter(
            should=[
                FieldCondition(key="labels", match=MatchAny(any=["bug", "critical"])),
                FieldCondition(key="assignee", match=MatchValue(value="unassigned"))
            ]
        )
    ]
)
# Returns: GitHub issues that are either labeled as bug/critical OR unassigned
```

### Null and Empty Checks

Check for missing or empty fields:

```python
from qdrant_client.http.models import IsNullCondition, IsEmptyCondition

# Find items without an assignee
Filter(
    must=[
        IsNullCondition(is_null={"key": "assignee"})
    ]
)

# Find items with empty tags array
Filter(
    must=[
        IsEmptyCondition(key="tags")
    ]
)
```


## Next Steps

- Explore [search examples](https://github.com/airweave-ai/airweave/tree/main/examples/04_advanced_search_with_filters.ipynb) with real-world filtering scenarios
- Review the [API reference](/api-reference/collections/search-collection-advanced-collections-readable-id-search-post?explorer=true) for complete filter specifications
- Learn about [search concepts](/search/concepts) for a comprehensive understanding
